package com.atguigu.springcloud.controller;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.atgui.springcloud.base.CommonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

@RestController
@RequestMapping("/api")
public class OpenApiController implements ApplicationContextAware {

    private static final Logger log = LoggerFactory.getLogger(OpenApiController.class);
    private ApplicationContext applicationContext;

    @Value("${server.port}")
    private String servicePort;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    @RequestMapping(value = {"/{serviceName}/{method}"},method = {RequestMethod.POST})
    public Object post(@PathVariable("serviceName") String serviceName, @PathVariable("method") String method , @RequestBody String params, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
        long startTime = System.currentTimeMillis();
        Object object = this.doService(serviceName, method, params);
        long executeTime = System.currentTimeMillis() - startTime;
        log.info("调用服务[{}.{}],调用端口[{}]执行时间：{}ms", new Object[]{serviceName, method, executeTime,servicePort});
        return object;
    }

    /**
     * 执行具体方法
     * @param serviceName
     * @param method
     * @param params
     * @return
     */
    private Object doService(String serviceName, String method, String params) {
        CommonResult commonResult = new CommonResult();
        commonResult.setCode(200);
        commonResult.setPort(servicePort);
        commonResult.setMessage("响应成功");
        Object serviceBean = this.getServiceBean(serviceName);
        Object callResult =null;
        if (serviceBean == null) {
            commonResult.setCode(999999);
            commonResult.setMessage("响应参数失败");
            log.info("调用服务[{}.{}]响应结果：{}", new Object[]{serviceName, method, JSONObject.toJSONString(commonResult)});
            return commonResult;
        } else {
            Method currentMethod = this.getInvokeMethod(serviceBean, method);
            if (currentMethod == null) {
                commonResult.setCode(999998);
                commonResult.setMessage("方法不存在："+method);
                log.info("调用服务[{}.{}]响应结果：{}", new Object[]{serviceName, method, JSONObject.toJSONString(commonResult)});
                return commonResult;
            } else {
                Type[] paramTypes = currentMethod.getGenericParameterTypes();

                if (paramTypes.length == 0){// 无参方法

                    try {
                        callResult = currentMethod.invoke(serviceBean);
                        commonResult.setData(callResult);
                    } catch (IllegalAccessException e) {
                        commonResult.setCode(999995);
                        commonResult.setMessage("调用无参方法出错");
                        log.error("调用无参方法出错：",e);
                    } catch (InvocationTargetException e) {
                        commonResult.setCode(999994);
                        commonResult.setMessage("调用无参方法出错");
                        log.error("调用无参方法出错：",e);
                    }

                }else if (paramTypes.length==1){ // 一个参数(常规都是这种)
                    Object inputParam = JSONObject.parseObject(params, paramTypes[0], new Feature[0]);
                    try {
                        log.info("调用服务[{}.{}]请求参数：{}", new Object[]{serviceName, method, JSONObject.toJSONString(inputParam)});
                        callResult = currentMethod.invoke(serviceBean,inputParam);
                        log.info("调用服务[{}.{}]响应参数：{}", new Object[]{serviceName, method, JSONObject.toJSONString(callResult)});
                        commonResult.setData(callResult);
                    } catch (IllegalAccessException e) {
                        commonResult.setCode(999993);
                        commonResult.setMessage("调用无参方法出错");
                        log.info("调用有参方法方法出错：",e);
                    } catch (InvocationTargetException e) {
                        commonResult.setCode(999993);
                        commonResult.setMessage("调用有参方法出错");
                        log.info("调用有参方法出错",e);
                    }catch (Exception e){
                        commonResult.setCode(999992);
                        commonResult.setMessage("调用有参方法出错");
                        log.info("调用有参方法出错",e);
                    }
                }else {
                    commonResult.setCode(999997);
                    commonResult.setMessage("参数个数不合法");
                    return commonResult;
                }

                return commonResult;
            }
        }
    }

    private Object getServiceBean(String serviceName){
        Object serviceBean =null;
        try {
            serviceBean= applicationContext.getBean(serviceName);
        }catch (Exception ex){
            log.error("获取[{}]服务失败,失败原因:",serviceName,ex);
        }
        return serviceBean;
    }

    private Method getInvokeMethod(Object serviceBean,String method){
        Method currentMethod = null;
        Method[] methods = serviceBean.getClass().getDeclaredMethods();
        Method[] me = methods;
        int length = methods.length;

        for(int i = 0; i < length; ++i) {
            Method method1 = me[i];
            if (method1.getName().equals(method)) {
                currentMethod = method1;
            }
        }

        return currentMethod;
    }


}
